<?php

namespace Xrfg\Wallet\TRX\Services;

use Exception;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
use App\Models\Coin;
use App\Models\Withdraw;
use App\Models\Wtrx;
use Xrfg\Wallet\TRX\Traits\TRXHelper;

/**
 * @method string eth_blockNumber()
 * @method array  eth_getBlockByNumber(string $blockNumber, bool $true)
 * @method array  eth_getLogs(array $options)
 * @method        personal_sendTransaction(array $array, string $password)
 */
class TRXWallet
{
    use TRXHelper;

    public $tron;

    public $config;

    /**
     * ETHService constructor.
     *
     * @param array $config
     */
    public function __construct(array $config)
    {
        $this->config = $config;
        $fullNode = new \IEXBase\TronAPI\Provider\HttpProvider((string)$config['full_url']);
        $solidityNode = new \IEXBase\TronAPI\Provider\HttpProvider((string)$config['solitidy_url']);
        $eventServer = new \IEXBase\TronAPI\Provider\HttpProvider((string)$config['event_url']);

        try {
            $this->tron = new \IEXBase\TronAPI\Tron($fullNode, $solidityNode, $eventServer);
        } catch (\IEXBase\TronAPI\Exception\TronException $e) {
            Log::error($e->getMessage());
            exit('TRX 连接失败');
        }
    }

    /**
     * 创建钱包地址.
     * @return array
     */
    public function newAccount()
    {
        try {
            $res = $this->tron->createAccount();

            $wtrx = new Wtrx();
            $wtrx->address = $res['address'];
            $wtrx->hex_address = $res['hexAddress'];
            $wtrx->private_key = $res['privateKey'];
            $wtrx->save();

            return $wtrx->address;
        } catch (Exception $exception) {
            Log::error($exception);
            return null;
        }
    }

    /**
     * 查询余额.
     * @param $address
     * @return float
     */
    public function getBalance($address)
    {
        $this->tron->setAddress($address);

        return $this->tron->getBalance(null, true);
    }

    /**
     * TRX转账.
     * @param $from base58地址
     * @param $fromPrivateKey 私钥
     * @param $to base58地址
     * @param $number 数量
     * @return null
     */
    public function doTransferTRX($from, $fromPrivateKey, $to, $number)
    {
        $from = strtoupper($this->base58check2HexString($from)); // 16进制
        $to = strtoupper($this->base58check2HexString($to)); // 16进制
        try {
            $this->tron->setAddress($from);
            $this->tron->setPrivateKey($fromPrivateKey);
            $result = $this->tron->send($to, $number);
            return $result['txID'];
        } catch (Exception $exception) {
            logger('==TRX转账失败==');
            Log::error($exception);
            return null;
        }
    }

    /**
     * TRC20转账.
     * @param $coinName 币种名称
     * @param $from_address base58地址
     * @param $fromPrivateKey 私钥
     * @param $to_address base58地址
     * @param $number 数量
     * @return null
     */
    public function doTransferTRC20($coinName, $from_address, $fromPrivateKey, $to_address, $number)
    {
        $coinName = strtoupper($coinName);
        $coin = Coin::where('name', $coinName)->first();
        if (!$coin) {
            return null;
        }

        // 合约地址
        $contract_address = config("wallet.trx.contracts.{$coinName}.contractAddress"); // base58
        $contract_address = strtoupper($this->base58check2HexString($contract_address)); // 16进制
        $to_address = strtoupper($this->base58check2HexString($to_address)); // 16进制
        // 合约小数位
        $decimals = config("wallet.trx.contracts.{$coinName}.decimals");
        $function_selector = "transfer(address,uint256)";

        $owner_address = strtoupper($this->base58check2HexString($from_address));
        $fee_limit = 100000000;
        $call_value = 0;
        $parameter = $this->address_to_param($to_address) . str_pad(substr($this->ether2wei($number, $decimals), 2), 64, '0', STR_PAD_LEFT);

        try {
            $http = new Client();
            $response = $http->request('POST',"{$this->config['full_url']}/wallet/triggersmartcontract",[
                'json' => [
                    'contract_address' => $contract_address,
                    'function_selector' => $function_selector,
                    'parameter' => $parameter,
                    'fee_limit' => $fee_limit,
                    'call_value' => $call_value,
                    'owner_address' => $owner_address,
                ]
            ]);

            logger('==============TRC20-USDT转出==================');
            $tx = $response->getBody()->getContents();
            logger($tx);
            $data = (json_decode($tx, true))['transaction'];

            $response = $http->request('POST',"{$this->config['full_url']}/wallet/gettransactionsign",[
                'json' => [
                    'transaction' =>$data,
                    'privateKey' => $fromPrivateKey,
                ]
            ]);
            logger('==============TRC20-USDT签名==================');
            $signTx = $response->getBody()->getContents();
            logger($signTx);
            $data = (json_decode($signTx ,true));
            logger($data);



            $response = $http->request('POST',"{$this->config['full_url']}/wallet/broadcasttransaction",[
                'json' =>$data
            ]);
            logger('==============TRC20-USDT广播==================');
            $brocastTx = $response->getBody()->getContents();
            logger($brocastTx);
            $data = (json_decode($brocastTx ,true));

            return $data['txid'];

        } catch (Exception $exception) {
            logger('==TRC20转账失败==');
            Log::error($exception);
            return null;
        }
    }

    /**
     * 查询最新区块.
     * @return array
     */
    public function getCurrentBlock()
    {
        return $this->tron->getCurrentBlock();
    }

    public function hexString2Address($sHexString)
    {
        return $this->tron->hexString2Address($sHexString);
    }

    /**
     * 查询交易.
     * @param $number
     * @return array
     */
    public function getBlockByNumber($number)
    {
        return $this->tron->getBlockByNumber($number);
    }

    public function transferTRX(Withdraw $withdraw)
    {
        try {
            $hash = $this->doTransferTRX(config('wallet.trx.withdraw_address'), config('wallet.trx.password'), $withdraw->address, $withdraw->number());
            if ($hash) {
                $withdraw->hash = $hash;
                $withdraw->status = Withdraw::STATUS_SUCCESS;
                $withdraw->save();
            }
        } catch (Exception $exception) {
            Log::error($exception);
        }
    }

    public function transferTRC20(Withdraw $withdraw)
    {
        $coinName = Coin::find($withdraw->coin_id)->name;
        try {
            $hash = $this->doTransferTRC20($coinName, config('wallet.trx.withdraw_address'), config('wallet.trx.password'), $withdraw->address, $withdraw->number());
            if ($hash) {
                $withdraw->hash = $hash;
                $withdraw->status = Withdraw::STATUS_SUCCESS;
                $withdraw->save();
            }
        } catch (Exception $exception) {
            Log::error($exception);
        }
    }
}
